메인 컨텐츠로 건너뛰기

TDD와 Unit Test

TDD테스트

서론

최근 이상한 변호사 우영우라는 드라마에 빠져살고있다

작중 주인공의 이런 대사가있다.

이 사건은 재미있습니다😂 제가 좋아하는😆고래🐳퀴즈❓같아요. 몸무게가🏋️ 22톤인 암컷 향고래가 500kg에 달하는 대왕오징어를🦑 먹고 🍽 6시간 뒤 1.3톤짜리 알을🥚낳았다면 이 암컷 향고래의 몸무게는🏋️얼마일까요? 정답은 '고래는🐳 알을🥚낳을 수 없다'입니다. 고래는🐳포유류라 알이🥚아닌새끼를👶 낳으니까요. 무게에만 초점을🤨맞추면 문제를 풀 수 없습니다.핵심을 봐야🧐돼요.

위 대사로 카톡방에서 대화를 하다가 ~~(영업을 하다가)~~ 문득 최근 JUnit5를 학습하고 있는 스스로에게 질문해봤다.

  • 테스트를 왜 사용해야하는지?
  • 단위테스트가 뭔가요?
  • 테스트의 종류는 뭐가있는지 알고있나요? 등등..
  • TDD가 뭔가요?
    • Test-Driven-Development인건 아는데 왜 이 방식을 사용하죠? 이점과 단점을 알고있나요?

전혀 대답하지 못했다. 평소 학습할 때 Top-Bottom 방식을 좋아하지만 이건 시작부터 너무 Bottom이 없는거같다. JUnit5에 초점을 두고의 사용법 및 여타 프레임워크들의 사용방법을 아는것도 중요하지만 개념도 중요하다.

~~JUnit5에만 초점을🤨맞추면 제대로된 테스트를 짤 수 없습니다. 핵심을 봐야🧐돼요.~~

개념을 잡으면서 테스트의 필요성을 절실히 느껴보자.

Test

테스트를 왜 해야할까? 당연한 질문에 당연한 답변이지만 우리는 사전에 문제를 검증하기 위해 테스트를 수행한다.

테스트의 종류

테스트는 대상 범위나 성격에 따라 UI Test, Integration Test(통합 테스트), Unit Test(단위 테스트) 등 3가지로 구분한다.

drawing

단위 테스트(Unit Test)

하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트다.

단위 테스트를 사용하면 다음과 같은 이점이 있다.

  • 테스팅에 대한 시간과 비용 절감
  • 새로운 기능 추가 시 빠르게 테스트 가능
  • 리팩토링 시 안정성 확보 가능
  • 테스트가 코드에 대한 문서가 될 수 있음

통합 테스트(Integration Test)

서로 다른 모듈 혹은 클래스간의 상호작용의 유효성을 검사하는 테스트다. 각각의 단위테스트가 검증되었다해도 모듈간 인터페이스 및 데이터 흐름이 의도한 대로 동작하지 않는 경우를 고려해 조금 더 넓은 범위에서 테스트를 수행해야 할 필요성이 있다.

UI Test

대형 테스트로 분류되어 실제 사용자들이 사용하는 화면에 대한 테스트를 하여 서비스의 기능이 정상적을 ㅗ작동하는지 검증하는 테스트다. 화면과 직접적으로 연관되어있는 테스트이다보니 실행시간 및 유지보수비용이 크다.

테스트 주도 개발(TDD)

TDD(Test-Driven Development)는 테스트코드를 먼저 작성하는 개발 방법론이다. 이는 깔끔한 코드작성, 장기적 개발비용 절감 등의 이점을 가지고있다.

테스트를 먼저 쓰라니... 귀찮고 개발이 오히려 더뎌지는 느낌이 든다. 그러나 이전에 작성한 프로젝트들을 보면 테스트가 없어 기능 확인을 하려면 일일히 프로젝트를 실행해야하는 번거로움이 보인다. 프로젝트 규모가 엄청 커지고 장기화되면서 인수인계간 문제가 없으려면...? 🧐 필요성이 슬슬 느껴진다.🤔

순서

  1. 실패하는 작은 단위 테스트를 작성한다. (컴파일조차 되지 않을 수 있다)
  2. 빨리 테스트를 통과하기 위해 프로덕션 코드를 작성한다.
  3. 그 다음의 테스트 코드를 작성한다. (실패 테스트가 없을 경우에만 성공 테스트를 작성한다)
  4. 새로운 테스트를 통과하기 위해 프로덕션 코드를 추가 또는 수정한다.
  5. 1~4단계를 반복하여 실패/성공의 모든 테스트 케이스를 작성한다.
  6. 개발된 코드들에 대해 모든 중복을 제거하며 리팩토링한다.

실패하는 테스트 코드를 작성할 때까지 실제 코드를 작성하지 않는다.

접근방법

디자인(설계) 단계에서 프로그래밍 목적을 반드시 미리 정의해야만 하고, 무엇보다 테스트해야 할지 미리 정의(테스트 케이스 작성)해야만 한다.

테스트 코드를 작성하는 도중 발생하는 예외 사항(버그 및 수정사항)은 테스트 케이스에 추가하고 설계를 개선한다.

이후 테스트가 통과된 코드만을 코드 개발 단계에서 실제 코드로 작성한다.

Spring 에서는 TDD를 어떻게 접근해야할까? Controller, Service, Repository... 어디부터 테스트를 적용해야할지 감이 잘 오지 않는다. TDD와 일반적인 개발 방식의 가장 큰 차이점은 테스트 코드를 작성한 뒤에 실제 코드를 작성한다는 것이다. 해당 글을 참고했다.

Spring에서 TDD

  • Repository -> Service -> Controller 순서로 개발을 진행한다.
  • Repository 계층의 테스트는 H2와 같은 인메모리 데이터베이스 기반의 통합 테스트로 진행한다.
  • Service 계층의 테스트는 Mockito를 사용해 Repository 계층을 Mock하여 진행한다.
  • Controller 계층의 테스트는 SpringTest의 MockMvc를 사용해 진행한다.

Repository 계층이 다른 계층에 대한 의존성이 거의 없기 때문에 Repository에 대한 테스트를 먼저 작성하는것이 좋아보인다고 한다. Controller 먼저 짜도 문제될건 없으며 이는 개인 취향차이로 보인다고 한다.

Reference

https://mangkyu.tistory.com/182 https://wooaoe.tistory.com/33 https://hanamon.kr/tdd%EB%9E%80-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C/